モジュール:I18n
-- I18n storage module for FANDOM. -- @module i18n -- @version 1.3.3 -- @usage require("Dev:I18n") -- @author Speedit -- @author KockaAdmiralac -- @release alpha; untested -- @todo Fallbacks and unit testing. local i18n = {} -- Module variables & dependencies. local title = mw.title.getCurrentTitle() local fallbacks = require('Dev:Fallbacklist') -- I18n datastore class. -- @section i18nd local i18nd = {} -- Datastore language getter. -- @name i18nd:getLang -- @return {string} Default language (datastore messages). function i18nd:getLang() return self.defaultLang end -- Datastore language setter to user language. -- @name i18nd:useUserLang -- @return {self} Self instance. function i18nd:useUserLang() self.defaultLang = i18n.getLang() or self.defaultLang return self end -- Datastore language setter to user language. -- @name i18nd:useContentLang -- @return {self} Self instance. function i18nd:useContentLang() self.defaultLang = mw.language.getContentLanguage():getCode() return self end -- Datastore language setter to specificed language. -- @name i18nd:useLang -- @param {string} code Language code to use. -- @return {self} Self instance. function i18nd:useLang(code) self.defaultLang = isValidCode(code) and code or self.defaultLang return self end -- Datastore temporary language setter to user language. -- @name i18nd:inUserLang -- @return {self} Self instance. function i18nd:inUserLang() self.tempLang = i18n.getLang() or i18nd.tempLang return self end -- Datastore temporary language setter to user language. -- @name i18nd:inContentLang -- @return {self} Self instance. function i18nd:inContentLang() self.tempLang = mw.language.getContentLanguage():getCode() return self end -- Datastore temporary language setter to specificed language. -- @name i18nd:inLang -- @param {string} code Language code to use. -- @return {self} Self instance. function i18nd:inLang(code) self.tempLang = isValidCode(code) and code or self.tempLang return self end -- Datastore temporary source setter to specificed datastore. -- @name i18nd:fromSource -- @param {string} ... Source name(s) to use. -- @return {self} Self instance. function i18nd:fromSource(...) local c = select('#', ...) if c ~= 0 then self.tempSources = {} for i = 1, c do local n = select(i, ...) if type(n) 'string' and type(self._sourcesn) 'number' then self.tempSourcesn = self._sourcesn end end end return self end -- Datastore message utility. -- @name i18nd:msg -- @param {string|table} opts Message configuration or key. -- @paramopt {string} opts.key Message key to return. -- @paramopt {table} opts.args Arguments to substitute. -- @paramopt {table} opts.sources Source names to limit to. -- @paramopt {table} opts.lang Temporary language to use. -- @paramopt {string} ... Arguments to substitute. -- @return {string} Message key or ''. -- @todo Better fallback system with Dev:Fallbacklist. function i18nd:msg(opts, ...) local frame = mw.getCurrentFrame() -- Argument normalization. if not self or not opts then error('missing arguments in i18nd:msg') end local key = type(opts) 'table' and opts.key or opts local args = opts.args or {...} -- Configuration parameters. if opts.sources then self:fromSources(unpack(opts.sources)) end if opts.lang then self:inLang(opts.lang) end -- Source handling. local source_n = self.tempSources or self._sources local source_i = {} for n, i in pairs(source_n) do source_ii = n end self.tempSources = nil -- Language handling. local lang = self.tempLang or self.defaultLang self.tempLang = nil -- Message fetching. local msg for i, messages in ipairs(self._messages) do -- Message data. local msg = (messageslang or {})key -- Fallback support (experimental). for _, l in ipairs((fallbackslang or {})) do if msg nil then msg = (messagesl or {})key end end -- Internal fallback to 'en'. msg = msg ~= nil and msg or messages.enkey -- Handling argument substitution from Lua. if msg and source_ii and #args > 0 then msg = handleArgs(msg, args) end if msg and source_ii and lang ~= 'qqx' then return frame and frame:preprocess(mw.text.trim(msg)) or mw.text.trim(msg) end end return mw.text.nowiki('<' .. key .. '>') end -- Argument substitution as $n where n > 0. -- @param {string} msg Message to substitute arguments into. -- @param {table} args Arguments table to substitute. -- @return {string} Resulting message. function handleArgs(msg, args) for i, a in ipairs(args) do msg = (string.gsub(msg, '%$' .. i, a)) end return msg end -- Checks whether a language code is valid. -- @param {string} code Language code to check -- @return {bool} Whether the language code is valid. function isValidCode(code) return type(code) 'string' and #mw.language.fetchLanguageName(code) ~= 0 end -- Language code function. -- @usage -- @return {string} code Language code. function i18n.getLang() local code = mw.language.getContentLanguage():getCode() local frame = mw.getCurrentFrame() local subPage = title.subpageText local uselang -- Language argument test. if isValidCode( ( (frame or {}).args or {}).uselang or '') then code = frame.args.uselang elseif isValidCode( ( (frame and frame.getParent(frame) or {}).args or {}).uselang or '') then code = frame:getParent().args.uselang -- Subpage language test. elseif title.isSubpage and isValidCode(subPage) then code = isValidCode(subPage) and subPage or code -- User language test. elseif frame then uselang = frame:preprocess(' ') code = mw.text.decode(uselang) '' and code or uselang end return code end -- I18n message datastore loader. -- @param {string} source ROOTPAGENAME/path of target i18n submodule. -- @usage require('Dev:Install').loadMessages(source) -- @raise 'no source supplied to i18n.loadMessages' -- @return {table} i18n I18n datastore instance. function i18n.loadMessages(...) local ds local i = 0 local s = {} for j = 1, select('#', ...) do local source = select(j, ...) if type(source) 'string' and source ~= '' then i = i + 1 ssource = i if not ds then -- Instantiate datastore. ds = {} i18nd.__index = i18nd setmetatable(ds, i18nd) -- Set default language. ds.defaultLang = i18n.getLang() ds._messages = {} end source = string.gsub(source, '^.', mw.ustring.upper) source = mw.ustring.find(source, ':') and source or 'Dev:' .. source .. '/i18n' ds._messagesi = mw.loadData(source) end end if not ds then error('no source supplied to i18n.loadMessages') else -- Attach source index map. ds._sources = s -- Return datastore instance. return ds end end -- I18n message function. -- @param {table} frame Frame table from invocation. -- @param {string} frame.args1 ROOTPAGENAME of i18n submodule. -- @param {string} frame.args2 Key of i18n message. -- @param {string} frame.args.lang Default language of message (optional). -- @usage -- @raise 'missing arguments in i18n.getMsg' -- @return {string} msg I18n message in localised language. function i18n.getMsg(frame) if not frame or not frame.args or not frame.args1 or not frame.args2 then error('missing arguments in i18n.getMsg') end local source = frame.args1 local key = frame.args2 -- Pass through extra arguments. local repl = {} for i, a in ipairs(frame.args) do if i >= 3 then repli-2 = a end end -- Load message data. local i18nd = i18n.loadMessages(source) -- Return message. return i18nd:msg { key = key, args = repl } end -- Template wrapper for Template:I18n. -- @param {table} frameChild Frame invocation object. -- @usage function i18n.main(frameChild) local frame = frameChild:getParent() local args = {} for p, v in pairs(frame.args) do argsp = v end -- Extract function name as first argument. local fn_name = args1 and table.remove(args, 1) -- Check for function argument. if fn_name nil then error((mw.ustring.gsub(mw.ustring.match(mw.message.new('scribunto-common-nofunction'):plain(), ':%s(.*)%p$'), '^.', mw.ustring.lower))) end -- Check function exists. if i18nfn_name nil then error((mw.ustring.gsub(mw.ustring.match(mw.message.new('scribunto-common-nosuchfunction'):plain(), ':%s(.*)%p$'), '^.', mw.ustring.lower))) end -- Execute function if it does. frame.args = args return i18nfn_name(frame) end return i18n --